/**
 * Created by Richard Radlherr.
 * Date: 16.06.2006 10:23
 */
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace TagTool.GraphicTypes
{
	[Serializable()]
	public class PointD
	{
		double x;
		double y;
		double z;
		public static readonly PointD Origin = new PointD(0.0, 0.0, 0.0);
		public PointD()
		{
		}

		public PointD(double x, double y, double z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}
		
		public PointD(PointD p)
		{
			this.x = p.X;
			this.y = p.Y;
			this.z = p.Z;
		}
		
		public double X
		{
			get {return x; }
			set { x = value; }
		}
		
		public double Y
		{
			get {return y; }
			set { y = value; }
		}
		
		public double Z
		{
			get {return z; }
			set { z = value; }
		}
		
		public override string ToString()
		{
			return String.Format("({0}; {1}; {2})", x.ToString(), y.ToString(), z.ToString());
		}
		
		public override bool Equals(object obj)
		{
			return obj != null && obj.GetType() == this.GetType() && x == ((PointD)obj).X && y == ((PointD)obj).Y && z == ((PointD)obj).Z;
		}
		
		public override int GetHashCode()
		{
			return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
		}
		
		public PointD Multiply(double factor)
		{
			return new PointD(x * factor, y * factor, z * factor);
		}
		
		public double Length
		{
			get {return Math.Sqrt(x*x + y*y + z*z); }
		}
		
		public double Length2
		{
			get { return x*x + y*y + z*z; }
		}
		
		
		public PointD Normalize()
		{
			double l = Length;
			if (l != 0.0)
			{
				return new PointD(x / l, y / l, z / l);
			}
			return new PointD();
		}
		
		public static PointD operator + (PointD q, PointD p)
		{
			return new PointD(q.x + p.x, q.y + p.y, q.z + p.z);
		}
		
		public static PointD operator - (PointD q,PointD p)
		{
			return new PointD(q.x - p.x, q.y - p.y, q.z - p.z);
		}
		
		public static PointD operator * (PointD p, double d)
		{
			return new PointD(p.x * d, p.y * d, p.z * d);
		}
		
		public static PointD operator / (PointD q, double d)
		{
			return new PointD(q.x / d, q.y / d, q.z / d);
		}
		
		public static double operator * (PointD p, PointD q)
		{
			return (q.x * p.x + q.y * p.y + q.z * p.z);
		}
		
		public static bool operator == (PointD p, PointD q)
		{
			if (p == null && q == null)
			{
				return true;
			}
			if (p == null ||q == null)
			{
				return false;
			}
			
			return (q.x == p.x &&  q.y == p.y && q.z == p.z);
		}
		
		public static bool operator != (PointD p, PointD q)
		{
			if (p == null && q == null)
			{
				return false;
			}
			if (p == null ||q == null)
			{
				return true;
			}
			
			return (q.x != p.x &&  q.y != p.y && q.z != p.z);
		}
		
		public double Angle(PointD p)
		{
			return Math.Acos(x * p.x + y * p.y + z * p.z);
		}

		public void Add(double x, double y, double z)
		{
			this.x += x;
			this.y += y;
			this.z += z;
		}
	}
	
}
